﻿/*  
    Copyright (C) <2007-2013>  <Kay Diefenthal>

    ArgusTv.UI.MediaCenter is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    ArgusTv.UI.MediaCenter is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with ArgusTv.UI.MediaCenter.  If not, see <http://www.gnu.org/licenses/>.
*/

using System;
using System.Collections.Generic;
using ArgusTV.DataContracts;
using ArgusTV.ServiceAgents;
using ArgusTV.UI.MediaCenter.Logging;
using ArgusTV.UI.MediaCenter.Properties;
using ArgusTV.UI.MediaCenter.Views;
using Microsoft.MediaCenter;
using Microsoft.MediaCenter.Hosting;
using Microsoft.MediaCenter.UI;

namespace ArgusTV.UI.MediaCenter.ViewModels
{
    public class LiveModel :ModelItem
    {
        #region Private Fields

        private readonly HistoryOrientedPageSession _session;
        private readonly AddInHost _host;
        private readonly ChannelType _channelType;
        private Channel _channel;
        private readonly Timer _delayTimer;
        private readonly Timer _keepAliveTimer;
        private LiveStream _liveStream;
        private LiveStreamResult _liveStreamResult;

        #endregion

        #region Constructor

        /// <summary>
        /// LiveModel
        /// </summary>
        /// <param name="session"></param>
        /// <param name="host"></param>
        /// <param name="type"></param>
        public LiveModel(HistoryOrientedPageSession session, AddInHost host, Int32 type)
        {
            _session = session;
            _host = host;
            _channelType = (ChannelType) type;
            _delayTimer = new Timer {Enabled = true, Interval = 3000, AutoRepeat = false};
            _delayTimer.Tick += OnDelayTimerTick;
            _keepAliveTimer = new Timer {Enabled = true, Interval = 10000, AutoRepeat = true};
            _keepAliveTimer.Tick += OnKeepAliveTimerTick;
        }

        #endregion

        #region Properties

        /// <summary>
        /// MediaCenterEnvironment
        /// </summary>
        public MediaCenterEnvironment MediaCenterEnvironment
        {
            get
            {
                if (_host == null) return null;
                return _host.MediaCenterEnvironment;
            }
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Initialize a new Instance of <see cref="LiveView"/> Class.
        /// </summary>
        /// <returns></returns>
        private LiveView CreateLiveView()
        {
            try
            {
                var view = new LiveView();
                view.Informations = new ArrayListDataSet(view);
                RetrieveChannelGroups(view);
                return view;
            }
            catch (Exception exception)
            {
                Logger.Error(string.Format("{0}{1}:{2}", "LiveModel", "CreateLiveView", exception));
                return null;
            }
        }

        /// <summary>
        /// RetrieveChannelGroups
        /// </summary>
        /// <param name="view"></param>
        private void RetrieveChannelGroups(LiveView view)
        {
            try
            {
                var list = new ArrayListDataSet(view);
                using (var schedulerServiceAgent = new SchedulerServiceAgent())
                {
                    var channelgroups = schedulerServiceAgent.GetAllChannelGroups(_channelType, true);
                    if (channelgroups.Length == 0)
                    {
                        var all = new ChannelGroup();
                        switch (_channelType)
                        {
                            case ChannelType.Television:
                                all.GroupName = "All";
                                all.ChannelGroupId = ChannelGroup.AllTvChannelsGroupId;
                                list.Add(all);
                                break;
                            case ChannelType.Radio:
                                all.GroupName = "All";
                                all.ChannelGroupId = ChannelGroup.AllRadioChannelsGroupId;
                                list.Add(all);
                                break;
                        }
                    }
                    else
                    {
                        list.CopyFrom(channelgroups);
                    }
                }
                var group = new Choice(view, null, list) {Chosen = list[0]};
                view.GroupChanged += delegate(object sender, EventArgs e)
                    {
                        var liveview = (LiveView) sender;
                        var selected = (ChannelGroup) liveview.Groups.Chosen;
                        view.SubTitle = selected.GroupName;
                        RetrieveChannelsForGroup(liveview, selected.ChannelGroupId);
                    };
                view.Groups = group;
                RetrieveChannelsForGroup(view, ((ChannelGroup) view.Groups.Chosen).ChannelGroupId);
            }
            catch (Exception exception)
            {
                Logger.Error(string.Format("{0}{1}:{2}", "LiveModel", "RetrieveChannelGroups", exception));
            }
        }

        /// <summary>
        /// RetrieveChannelsForGroup
        /// </summary>
        /// <param name="view"></param>
        /// <param name="groupId"></param>
        private void RetrieveChannelsForGroup(LiveView view, Guid groupId)
        {
            try
            {
                var list = new ArrayListDataSet(view);
                using (var schedulerServiceAgent = new SchedulerServiceAgent())
                {
                    var channels = schedulerServiceAgent.GetChannelsInGroup(groupId, true);
                    list.CopyFrom(channels);
                }

                var choice = new Choice(view, null, list) {Chosen = (Channel) list[0]};
                view.Channels = choice;
                if (list.Count > 0)
                {
                    view.ChannelChanged += delegate(object sender, EventArgs e)
                        {
                            var liveview = (LiveView) sender;
                            var selected = (Channel) liveview.Channels.Chosen;
                            RetrieveInformations(liveview, selected);
                            _delayTimer.Stop();
                            _delayTimer.Start();
                        };
                }
            }
            catch (Exception exception)
            {
                Logger.Error(string.Format("{0}{1}:{2}", "LiveModel", "RetrieveChannelsForGroup", exception));
            }
        }

        /// <summary>
        /// RetrieveInformations
        /// </summary>
        /// <param name="view"></param>
        /// <param name="channel"></param>
        private void RetrieveInformations(LiveView view, Channel channel)
        {
            _channel = channel;
            view.Informations.Clear();
            try
            {
                using (var schedulerServiceAgent = new SchedulerServiceAgent())
                {
                    CurrentAndNextProgram programs = schedulerServiceAgent.GetCurrentAndNextForChannel(
                        channel.ChannelId, false, _liveStream);
                    if (programs.Current == null || programs.Next == null)
                    {
                        view.Informations.Add(new Information(channel.DisplayName, "No Data aviable!",
                                                              "Please check if the channel is checked to grab guide"));
                    }
                    else
                    {
                        view.Informations.Add(new Information(channel.DisplayName,
                                                              programs.Current.StartTime.ToShortTimeString() + " - " +
                                                              programs.Current.StopTime.ToShortTimeString() + " : " +
                                                              programs.Current.Title,
                                                              programs.Next.StartTime.ToShortTimeString() + " - " +
                                                              programs.Next.StopTime.ToShortTimeString() + " : " +
                                                              programs.Next.Title));
                    }
                }
            }
            catch (Exception exception)
            {
                Logger.Error(string.Format("{0}{1}:{2}", "LiveModel", "RetrieveInformations", exception));
            }
        }

        /// <summary>
        /// IsStreaming
        /// </summary>
        /// <returns></returns>
        private Boolean IsStreaming()
        {
            if (_liveStream != null)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// IsPlaying
        /// </summary>
        /// <returns></returns>
        private Boolean IsPlaying()
        {
            if (MediaCenterEnvironment.MediaExperience.Transport.PlayState == PlayState.Playing)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// StopPlaying
        /// </summary>
        private void StopPlaying()
        {
            MediaCenterEnvironment.MediaExperience.Transport.PlayRate = 0;
        }

        /// <summary>
        /// StopStream
        /// </summary>
        private void StopStream()
        {
            _keepAliveTimer.Stop();
            using (var controlServiceAgent = new ControlServiceAgent())
            {
                controlServiceAgent.StopLiveStream(_liveStream);
            }
            _liveStream = null;
        }

        /// <summary>
        /// StartStream
        /// </summary>
        private void StartStream()
        {
            using (var controlServiceAgent = new ControlServiceAgent())
            {
                _liveStream = null;
                _liveStreamResult = controlServiceAgent.TuneLiveStream(_channel, ref _liveStream);
                if (_liveStreamResult == LiveStreamResult.ChannelTuneFailed)
                {
                    MediaCenterEnvironment.Dialog("Failed to tune to the requested channel.", "Channel Tuning Failed",
                                                  DialogButtons.Ok, 10, true);
                }
                if (_liveStreamResult == LiveStreamResult.IsScrambled)
                {
                    MediaCenterEnvironment.Dialog("The requested channel was scrambled", "Is Scrambled",
                                                  DialogButtons.Ok, 10, true);
                }
                if (_liveStreamResult == LiveStreamResult.NoFreeCardFound)
                {
                    StopPlaying();
                    StopStream();
                }
                if (_liveStreamResult == LiveStreamResult.NoRetunePossible)
                {
                    StopPlaying();
                    StopStream();
                }
                if (_liveStreamResult == LiveStreamResult.NotSupported)
                {
                    MediaCenterEnvironment.Dialog("Live streaming is not supported by this recorder. ", "Not Supported",
                                                  DialogButtons.Ok, 10, true);
                }
                if (_liveStreamResult == LiveStreamResult.Succeeded)
                {
                    var url = _liveStream.RtspUrl;
                    var urlitems = url.Split(new[] {':', '/', '/', ':', '/'});
                    var protocol = urlitems[0];
                    var port = urlitems[4];
                    var media = urlitems[5];
                    var ipaddress = Settings.Default.ServerIpAddress;
                    var newurl = Utils.RebuildMediaStreamUrl(protocol, ipaddress, port, media);

                    Play(newurl);
                    _keepAliveTimer.Enabled = true;
                    GoToEndOfStream();
                }
                if (_liveStreamResult == LiveStreamResult.UnknownError)
                {
                    MediaCenterEnvironment.Dialog("An unknown error occurred", "Unknown Error", DialogButtons.Ok, 10,
                                                  true);
                }
            }
        }

        /// <summary>
        /// OnDelayTimerTick
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnDelayTimerTick(object sender, EventArgs e)
        {
            if ((IsStreaming()) && (IsPlaying()))
            {
                StopPlaying();
                StopStream();
                StartStream();
            }
            StartStream();
        }

        /// <summary>
        /// OnKeepAliveTimerTick
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnKeepAliveTimerTick(object sender, EventArgs e)
        {
            try
            {
                using (var controlServiceAgent = new ControlServiceAgent())
                {
                    controlServiceAgent.KeepLiveStreamAlive(_liveStream);
                }
            }
            catch (Exception exception)
            {
                Logger.Error(string.Format("{0}{1}:{2}", "LiveModel", "OnKeepAliveTimerTick", exception));
            }
        }

        /// <summary>
        /// Play
        /// </summary>
        /// <param name="media"></param>
        private void Play(String media)
        {
            MediaCenterEnvironment.PlayMedia(MediaType.Video, media, false);
        }

        /// <summary>
        /// GoToEndOfStream
        /// </summary>
        private void GoToEndOfStream()
        {
            MediaCenterEnvironment.MediaExperience.Transport.Position = TimeSpan.MaxValue;
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Navigate to LiveView
        /// </summary>
        public void GoToLiveView()
        {
            try
            {
                var uiProperties = new Dictionary<string, object>();
                uiProperties["LiveView"] = CreateLiveView();
                _session.GoToPage("resx://ArgusTV.UI.MediaCenter/ArgusTV.UI.MediaCenter.Resources/LiveView",
                                  uiProperties);
            }
            catch (Exception exception)
            {
                Logger.Error(string.Format("{0}{1}:{2}", "LiveModel", "GoToLiveView", exception));

            }
        }

        #endregion
    }
}
